/*
 * (C) Copyright 2011-2015
 *
 * Yuri Tikhonov, Emcraft Systems, yur@emcraft.com
 * Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com
 * Vladimir Khusainov, Emcraft Systems, vlad@emcraft.com
 * Pavel Boldin, Emcraft Systems, paboldin@emcraft.com
 * Vladimir Skvortsov, Emcraft Systems, vskvortsov@emcraft.com
 * Anton Protopopov, Emcraft Systems, antonp@emcraft.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/*
 * Board specific code for the STmicro STM32F746 Discovery board
 */

#include <common.h>
#include <asm/io.h>
#include <asm/system.h>

DECLARE_GLOBAL_DATA_PTR;


/*
 * Init FMC/FSMC GPIOs based
 */
static int fmc_fsmc_setup_gpio(void)
{
	return 0;
}

static int rt1050_eth_pin_init(void){
    IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_40 = 4; // ENET_MDC
    IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_41 = 4; // ENET_MDIO
    IOMUXC_ENET_MDIO_SELECT_INPUT = 1; // MDIO input
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_04 = 3; // ENET_RX_DATA00
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_05 = 3; // ENET_RX_DATA01
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_06 = 3; // ENET_RX_EN
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_07 = 3; // ENET_TX_DATA00
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_08 = 3; // ENET_TX_DATA01
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_09 = 3; // ENET_TX_EN
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_10 = 3; // ENET_TX_CLK
    IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_11 = 3; // ENET_RX_ER
}
/*
 * MEM_WriteU32.
 */
void MEM_WriteU32(unsigned int addr, unsigned int data)
{
    (*(unsigned int *)(addr)) = data; 
}

/*
 * MEM_WriteU32.
 */
unsigned int MEM_ReadU32(unsigned int addr)
{
    return(*(unsigned int*)(addr));
}

/*
*
*/
void SDRAM_WaitIpCmdDone(void) 
{
  unsigned int reg;
  do
  {
      reg = MEM_ReadU32(0x402F003C);
  }while((reg & 0x3) == 0);
}

/*
 * Early hardware init.
 */
int board_init(void)
{
    
    // TODO: reversed to init SEMC pins
    rt1050_eth_pin_init();

	return 0;
}

/*
 * Dump pertinent info to the console.
 */
int checkboard(void)
{
    printf("Board: NXPRT1050 Rev %s, www.nxp.com\n",
            CONFIG_SYS_BOARD_REV_STR);

	return 0;
}

/*
 * STM32 RCC FMC specific definitions
 */
#define STM32_RCC_ENR_FMC		(1 << 0)	/* FMC module clock  */

static int dram_initialized = 0;

static inline u32 _ns2clk(u32 ns, u32 freq)
{
	uint32_t tmp = freq/1000000;
	return (tmp * ns) / 1000;
}

#define NS2CLK(ns) (_ns2clk(ns, freq))

/*
 * darm init
 */
int dram_init(void)
{
    /* TBD  */
    unsigned int temp = 0;

/*Init Sdram clk*/
  MEM_WriteU32(0x400FC068,0xffffffff);
  MEM_WriteU32(0x400FC06C,0xffffffff);
  MEM_WriteU32(0x400FC070,0xffffffff);
  MEM_WriteU32(0x400FC074,0xffffffff);
  MEM_WriteU32(0x400FC078,0xffffffff);
  MEM_WriteU32(0x400FC07C,0xffffffff);
  MEM_WriteU32(0x400FC080,0xffffffff);

  MEM_WriteU32(0x400D8030,0x00002001);
  //MEM_WriteU32(0x400D8100,0x00100000);  //100mhz
  //MEM_WriteU32(0x400FC014,0x00050D40);  //100mhz
  temp = MEM_ReadU32(0x400FC014);
  temp &= 0xFFFEFFFF;
  temp |= 0x00050040;
  MEM_WriteU32(0x400D8100,0x00100000);
  MEM_WriteU32(0x400FC014, temp); 
 // MEM_WriteU32(0x400FC014,0x00020D40); 


  printf("Clock Init Done \n");

/*Config IOMUX for sdr*/
  MEM_WriteU32(0x401F8014,0x00000000); // EMC_00
  MEM_WriteU32(0x401F8018,0x00000000); // EMC_01
  MEM_WriteU32(0x401F801C,0x00000000); // EMC_02
  MEM_WriteU32(0x401F8020,0x00000000); // EMC_03
  MEM_WriteU32(0x401F8024,0x00000000); // EMC_04
  MEM_WriteU32(0x401F8028,0x00000000); // EMC_05
  MEM_WriteU32(0x401F802C,0x00000000); // EMC_06
  MEM_WriteU32(0x401F8030,0x00000000); // EMC_07
  MEM_WriteU32(0x401F8034,0x00000000); // EMC_08
  MEM_WriteU32(0x401F8038,0x00000000); // EMC_09
  MEM_WriteU32(0x401F803C,0x00000000); // EMC_10
  MEM_WriteU32(0x401F8040,0x00000000); // EMC_11
  MEM_WriteU32(0x401F8044,0x00000000); // EMC_12
  MEM_WriteU32(0x401F8048,0x00000000); // EMC_13
  MEM_WriteU32(0x401F804C,0x00000000); // EMC_14
  MEM_WriteU32(0x401F8050,0x00000000); // EMC_15
  MEM_WriteU32(0x401F8054,0x00000000); // EMC_16
  MEM_WriteU32(0x401F8058,0x00000000); // EMC_17
  MEM_WriteU32(0x401F805C,0x00000000); // EMC_18
  MEM_WriteU32(0x401F8060,0x00000000); // EMC_19
  MEM_WriteU32(0x401F8064,0x00000000); // EMC_20
  MEM_WriteU32(0x401F8068,0x00000000); // EMC_21
  MEM_WriteU32(0x401F806C,0x00000000); // EMC_22
  MEM_WriteU32(0x401F8070,0x00000000); // EMC_23
  MEM_WriteU32(0x401F8074,0x00000000); // EMC_24
  MEM_WriteU32(0x401F8078,0x00000000); // EMC_25
  MEM_WriteU32(0x401F807C,0x00000000); // EMC_26
  MEM_WriteU32(0x401F8080,0x00000000); // EMC_27
  MEM_WriteU32(0x401F8084,0x00000000); // EMC_28
  MEM_WriteU32(0x401F8088,0x00000000); // EMC_29
  MEM_WriteU32(0x401F808C,0x00000000); // EMC_30
  MEM_WriteU32(0x401F8090,0x00000000); // EMC_31
  MEM_WriteU32(0x401F8094,0x00000000); // EMC_32
  MEM_WriteU32(0x401F8098,0x00000000); // EMC_33
  MEM_WriteU32(0x401F809C,0x00000000); // EMC_34
  MEM_WriteU32(0x401F80A0,0x00000000); // EMC_35
  MEM_WriteU32(0x401F80A4,0x00000000); // EMC_36
  MEM_WriteU32(0x401F80A8,0x00000000); // EMC_37
  MEM_WriteU32(0x401F80AC,0x00000000); // EMC_38
  MEM_WriteU32(0x401F80B0,0x00000010); // EMC_39, DQS PIN, enable SION
  MEM_WriteU32(0x401F80B4,0x00000000); // EMC_40
  MEM_WriteU32(0x401F80B8,0x00000000); // EMC_41
  
  // PAD ctrl
  MEM_WriteU32(0x401F8204,0x000000F1); // EMC_00
  MEM_WriteU32(0x401F8208,0x000000F1); // EMC_01
  MEM_WriteU32(0x401F820C,0x000000F1); // EMC_02
  MEM_WriteU32(0x401F8210,0x000000F1); // EMC_03
  MEM_WriteU32(0x401F8214,0x000000F1); // EMC_04
  MEM_WriteU32(0x401F8218,0x000000F1); // EMC_05
  MEM_WriteU32(0x401F821C,0x000000F1); // EMC_06
  MEM_WriteU32(0x401F8220,0x000000F1); // EMC_07
  MEM_WriteU32(0x401F8224,0x000000F1); // EMC_08
  MEM_WriteU32(0x401F8228,0x000000F1); // EMC_09
  MEM_WriteU32(0x401F822C,0x000000F1); // EMC_10
  MEM_WriteU32(0x401F8230,0x000000F1); // EMC_11
  MEM_WriteU32(0x401F8234,0x000000F1); // EMC_12
  MEM_WriteU32(0x401F8238,0x000000F1); // EMC_13
  MEM_WriteU32(0x401F823C,0x000000F1); // EMC_14
  MEM_WriteU32(0x401F8240,0x000000F1); // EMC_15
  MEM_WriteU32(0x401F8244,0x000000F1); // EMC_16
  MEM_WriteU32(0x401F8248,0x000000F1); // EMC_17
  MEM_WriteU32(0x401F824C,0x000000F1); // EMC_18
  MEM_WriteU32(0x401F8250,0x000000F1); // EMC_19
  MEM_WriteU32(0x401F8254,0x000000F1); // EMC_20
  MEM_WriteU32(0x401F8258,0x000000F1); // EMC_21
  MEM_WriteU32(0x401F825C,0x000000F1); // EMC_22
  MEM_WriteU32(0x401F8260,0x000000F1); // EMC_23
  MEM_WriteU32(0x401F8264,0x000000F1); // EMC_24
  MEM_WriteU32(0x401F8268,0x000000F1); // EMC_25
  MEM_WriteU32(0x401F826C,0x000000F1); // EMC_26
  MEM_WriteU32(0x401F8270,0x000000F1); // EMC_27
  MEM_WriteU32(0x401F8274,0x000000F1); // EMC_28
  MEM_WriteU32(0x401F8278,0x000000F1); // EMC_29
  MEM_WriteU32(0x401F827C,0x000000F1); // EMC_30
  MEM_WriteU32(0x401F8280,0x000000F1); // EMC_31
  MEM_WriteU32(0x401F8284,0x000000F1); // EMC_32
  MEM_WriteU32(0x401F8288,0x000000F1); // EMC_33
  MEM_WriteU32(0x401F828C,0x000000F1); // EMC_34
  MEM_WriteU32(0x401F8290,0x000000F1); // EMC_35
  MEM_WriteU32(0x401F8294,0x000000F1); // EMC_36
  MEM_WriteU32(0x401F8298,0x000000F1); // EMC_37
  MEM_WriteU32(0x401F829C,0x000000F1); // EMC_38
  MEM_WriteU32(0x401F82A0,0x000000F1); // EMC_39
  MEM_WriteU32(0x401F82A4,0x000000F1); // EMC_40
  MEM_WriteU32(0x401F82A8,0x000000F1); // EMC_41

  // Config SDR Controller Registers
  MEM_WriteU32(0x402F0000,0x10000004); // MCR
  MEM_WriteU32(0x402F0008,0x00030524); // BMCR0
  MEM_WriteU32(0x402F000C,0x06030524); // BMCR1
  MEM_WriteU32(0x402F0010,0x8000001D); // BR0, 32MB
  MEM_WriteU32(0x402F0014,0x8000001D); // BR1, 32MB
  MEM_WriteU32(0x402F0004,0x00000008); // IOCR, SEMC_CCSX0 as SDRAM_CS1
  MEM_WriteU32(0x402F0040,0x00000F31); // SDRAMCR0
  MEM_WriteU32(0x402F0044,0x00652922); // SDRAMCR1
  MEM_WriteU32(0x402F0048,0x00010920); // SDRAMCR2
  MEM_WriteU32(0x402F004C,0x50210A08); // SDRAMCR3
  MEM_WriteU32(0x402F0080,0x00000021); // DBICR0
  MEM_WriteU32(0x402F0084,0x00888888); // DBICR1
  MEM_WriteU32(0x402F0094,0x00000002); // IPCR1
  MEM_WriteU32(0x402F0098,0x00000000); // IPCR2

  MEM_WriteU32(0x402F0090,0x80000000); // IPCR0
  MEM_WriteU32(0x402F009C,0xA55A000F); // IPCMD, SD_CC_IPREA
  printf("Init sdram..\n");
  SDRAM_WaitIpCmdDone();
  MEM_WriteU32(0x402F0090,0x80000000); // IPCR0
  MEM_WriteU32(0x402F009C,0xA55A000C); // SD_CC_IAF
  SDRAM_WaitIpCmdDone();
  MEM_WriteU32(0x402F0090,0x80000000); // IPCR0
  MEM_WriteU32(0x402F009C,0xA55A000C); // SD_CC_IAF
  SDRAM_WaitIpCmdDone();
  MEM_WriteU32(0x402F00A0,0x00000033); // IPTXDAT
  MEM_WriteU32(0x402F0090,0x80000000); // IPCR0
  MEM_WriteU32(0x402F009C,0xA55A000A); // SD_CC_IMS
  SDRAM_WaitIpCmdDone();
    
  printf(" SDRAM Init Done \n");
    /*
     *   * Fill in global info with description of SRAM configuration
     *       */
     gd->bd->bi_dram[0].start = CONFIG_SYS_RAM_BASE;
            gd->bd->bi_dram[0].size  = CONFIG_SYS_RAM_SIZE;
            //dran_initialized = 1;

	return 0;
}

#ifdef CONFIG_MCFFEC
/*
 * Register the Ethernet driver
 */
int board_eth_init(bd_t *bis)
{
	return mcffec_initialize(bis);
}
#endif
